/*
 * gelifglcanvas.cpp
 *
 *  Created on: 2011-10-11
 *  Author    : gelif(admin@gelif.net)
 */
#include <cwchar>
#include <wx/dir.h>
#include <wx/wxprec.h>
#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif
#ifndef GAME_H
#include "game.h"
#endif
#include "gelifglcanvas.h"
////Event Table Start
BEGIN_EVENT_TABLE(GelifGLCanvas, wxGLCanvas) EVT_SIZE(GelifGLCanvas::OnSize)
    EVT_PAINT(GelifGLCanvas::onPaint)
    EVT_LEFT_DOWN(GelifGLCanvas::onLeftMouse)
    EVT_ERASE_BACKGROUND(GelifGLCanvas::onEraseBackground)
    EVT_IDLE(GelifGLCanvas::onIdle)
END_EVENT_TABLE()
////Event Table End

//----------------------------------------------------------------------------
// GelifGLCanvas
//----------------------------------------------------------------------------
GelifGLCanvas::GelifGLCanvas(GeliFrame *geliFrame, wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size) : wxGLCanvas(parent, id, NULL, pos, size)
{
    // get a handle on the host
    this->geliFrame = geliFrame;
    m_context = new wxGLContext(this);
    // initialize the board pieces and the mouse piece

    //int width, height;
    //GetClientSize(&width, &height);

    if (this->m_context)
    {
        this->SetCurrent(*m_context);
        wxPaintDC(this);
        glClearColor(0.0, 0.0, 0.0, 0.0);
        glClear(GL_COLOR_BUFFER_BIT);
        glViewport(0, 0, (GLint)this->GetSize().x, (GLint)this->GetSize().x);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluOrtho2D(0, Game::MAX_RANKS, 0, Game::MAX_FILES);
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
    }
    setupBoard();
    draw();
}

GelifGLCanvas::~GelifGLCanvas()
{
    delete m_context;
}

/////////////////////////////////////
// Chess-specific routines
/////////////////////////////////////

void GelifGLCanvas::setDefaultColors()
{
    color_square.Set(255, 255, 255);
    color_black_piece.Set(244, 000, 000);
    color_white_piece.Set(170, 180, 255);
    color_background.Set(63, 128, 128);
}

float GelifGLCanvas::getGLRed(wxColour &color)
{
    return (float)color.Red() / 255.0;
}

float GelifGLCanvas::getGLGreen(wxColour &color)
{
    return (float)color.Green() / 255.0;
}

float GelifGLCanvas::getGLBlue(wxColour &color)
{
    return (float)color.Blue() / 255.0;
}

void GelifGLCanvas::draw()
{
    // clear the window and put in the background color
    glClearColor(getGLRed(color_background), getGLGreen(color_background), getGLBlue(color_background), 1.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // draw the actual board
    drawBoard();
    if (this->geliFrame->game->status >= Game::IS_ON)
    {
        drawPieces();
    }
    if (this->geliFrame->game->status >= Game::BLACK_WIN)
    {
        drawFiveline();
    }
    // flush the GL buffer and then swap in a new one
    glFlush();
    SwapBuffers();
}

void GelifGLCanvas::drawBoard()
{
    glLineWidth(1.0);
    glDisable(GL_BLEND);
    glDisable(GL_TEXTURE_2D);
    glColor4f(1, 1, 1, 1);
    int n;
    for (n = 1; n <= Game::MAX_RANKS; n++) // draw y lines
    {
        glBegin(GL_LINES);
        glVertex2d(grid_width * n, grid_width);
        glVertex2d(grid_width * n, grid_width * Game::MAX_RANKS);
        glEnd();
    }
    for (n = 1; n <= Game::MAX_FILES; n++) // draw x lines
    {
        glBegin(GL_LINES);
        glVertex2d(grid_width, grid_width * n);
        glVertex2d(grid_width * Game::MAX_RANKS, grid_width * n);
        glEnd();
    }
}

void GelifGLCanvas::drawPieces()
{
    int x, y;
    for (x = 0; x < Game::MAX_FILES; x++)
    {
        for (y = 0; y < Game::MAX_RANKS; y++)
        {
            if (this->geliFrame->game->points[x][y] == Coordinate::BLACK)
            {
                this->drawBlackPiece(x, y);
            }
            else if (this->geliFrame->game->points[x][y] == Coordinate::WHITE)
            {
                this->drawWhitePiece(x, y);
            }
        }
    }
}

void GelifGLCanvas::drawBlackPiece(int x, int y)
{
    drawCircle(x, y, this->color_black_piece);
}

void GelifGLCanvas::drawWhitePiece(int x, int y)
{
    drawCircle(x, y, this->color_white_piece);
}

void GelifGLCanvas::drawCircle(int x, int y, wxColour color)
{
    const double PI = acos(-1);
    int angle;
    double dx = grid_width + x * grid_width;
    double dy = grid_width + y * grid_width;
    glBegin(GL_TRIANGLE_FAN);
    glColor3f(this->getGLRed(color), this->getGLGreen(color), this->getGLBlue(color));
    double radius = grid_width / 2.1;
    glVertex2d(dx, dy);
    for (angle = 0; angle <= 360; angle = angle + 1)
    {
        double px = dx + radius * cos(angle / 180.0 * PI);
        double py = dy + radius * sin(angle / 180.0 * PI);
        glVertex2d(px, py);
    }
    glEnd();
}

void GelifGLCanvas::drawFiveline()
{
    glLineWidth(6.0);
    glDisable(GL_BLEND);
    glDisable(GL_TEXTURE_2D);
    glColor3f(0, 1, 1);
    glBegin(GL_LINES);
    glVertex2d(grid_width * (this->geliFrame->game->fiveline->startX + 1),
            grid_width * (this->geliFrame->game->fiveline->startY + 1));
    glVertex2d(grid_width * (this->geliFrame->game->fiveline->endX + 1),
            grid_width * (this->geliFrame->game->fiveline->endY + 1));
    glEnd();
}

void GelifGLCanvas::getMouseBoardCoordinates()
{
    wxSize size = geliFrame->panelBoard->GetSize();
    x = Game::MAX_FILES * this->point.x / size.GetX() + 1;
    y = Game::MAX_RANKS - Game::MAX_RANKS * this->point.y / size.GetY();
}

void GelifGLCanvas::clearBoard()
{
    this->geliFrame->game->initStatus();
}

void GelifGLCanvas::setupBoard()
{
    clearBoard();
    //draw();
    //updateEverybody();
}

void GelifGLCanvas::updateEverybody()
{
    geliFrame->updateEverybody();
}

void GelifGLCanvas::sendMove(GelifMove &move)
{
    wxChar* move_str = move.serialize();
    size_t str_length = std::wcslen(move_str);
    geliFrame->poke(wxT("move"), move_str, str_length);
}

//////////////////////////////////////////////////////////////////////
// Event Handler Implementations
//////////////////////////////////////////////////////////////////////

void GelifGLCanvas::onPaint(wxPaintEvent& WXUNUSED(event))
{
    //wxPaintDC dc(this);
    //this->draw();
}

void GelifGLCanvas::onLeftMouse(wxMouseEvent& event)
{
    wxClientDC dc(this);
    PrepareDC(dc);
    this->geliFrame->PrepareDC(dc);
    this->point = event.GetLogicalPosition(dc);
    //int x = dc.DeviceToLogicalX(point.x);
    //int y = dc.DeviceToLogicalY(point.y);

    // convert these into board coordinates
    getMouseBoardCoordinates();

    if (event.LeftIsDown())
    {
        this->geliFrame->game->move(x, y);
    }
}

void GelifGLCanvas::onEraseBackground(wxEraseEvent& WXUNUSED(event))
{
    // Do Nothing to Avoid Flashing on MSW
}

void GelifGLCanvas::onIdle(wxIdleEvent& WXUNUSED(event))
{
    //this->draw();
}

void GelifGLCanvas::onKeyDown(wxKeyEvent& event)
{
    if (event.GetKeyCode() == WXK_SPACE)
    {
        wxCommandEvent e;
    }
    event.Skip();
}
